using AutoMapper;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System.IO;
using UniversalAdmin.Application.DTOs;
using UniversalAdmin.Application.Services;
using UniversalAdmin.Domain.Entities;
using UniversalAdmin.Domain.Repositories;
using UniversalAdmin.Infrastructure.Data.Contexts;

namespace UniversalAdmin.Infrastructure.Services;

public class DocumentService : IDocumentService
{
    private readonly IDocumentRepository _documentRepository;
    private readonly IDocumentChunkRepository _documentChunkRepository;
    private readonly IEmbeddingService _embeddingService;
    private readonly IMapper _mapper;

    public DocumentService(
        IDocumentRepository documentRepository,
        IDocumentChunkRepository documentChunkRepository,
        IEmbeddingService embeddingService,
        IMapper mapper)
    {
        _documentRepository = documentRepository;
        _documentChunkRepository = documentChunkRepository;
        _embeddingService = embeddingService;
        _mapper = mapper;
    }

    public async Task<DocumentDto> UploadDocumentAsync(Guid userId, IFormFile file, string? fileName = null)
    {
        try
        {
            // 优先使用传入的fileName，如果没有则使用file.FileName
            var documentTitle = !string.IsNullOrEmpty(fileName) 
                ? Path.GetFileNameWithoutExtension(fileName)
                : Path.GetFileNameWithoutExtension(file.FileName);
            
            var documentSource = !string.IsNullOrEmpty(fileName) ? fileName : file.FileName;
            
            var document = new Document
            {
                Title = documentTitle,
                Content = await ReadFileContentAsync(file),
                Source = documentSource,
                UploadedBy = userId,
                CreatedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow,
                CreateBy = userId.ToString(),
                UpdateBy = userId.ToString(),
                IsActive = true,
                IsDeleted = false
            };

            // 添加文档到上下文，但不立即保存
            var documentContext = (ApplicationDbContext)_documentRepository.GetContext();
            await documentContext.Documents.AddAsync(document);

            // 对文档进行分块和嵌入
            await ChunkDocumentAsyncWithoutSave(document);

            // 一次性保存所有更改
            await _documentRepository.SaveChangesAsync();

            return _mapper.Map<DocumentDto>(document);
        }
        catch (Exception ex)
        {
            // 记录详细错误信息
            // 如果是嵌入服务的异常，提供更具体的错误信息
            var errorMessage = ex.InnerException != null
                ? $"上传文档失败: {ex.Message} - {ex.InnerException.Message}"
                : $"上传文档失败: {ex.Message}";

            return new DocumentDto
            {
                ErrorMessage = errorMessage
            };
        }
    }

    public async Task<PagedResultDto<DocumentDto>> GetAllDocumentsAsync(Guid userId, int page = 1, int pageSize = 10, string? keyword = null)
    {
        // 直接查询数据库，不检查软删除状态
        var context = (ApplicationDbContext)_documentRepository.GetContext();
        var query = context.Documents
            .Where(d => d.UploadedBy == userId);

        if (!string.IsNullOrWhiteSpace(keyword))
        {
            query = query.Where(d => (d.Title != null && d.Title.Contains(keyword)) || (d.Content != null && d.Content.Contains(keyword)));
        }

        var totalItems = await query.CountAsync();
        var items = await query
            .OrderByDescending(d => d.CreatedAt)
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();

        return new PagedResultDto<DocumentDto>
        {
            Items = _mapper.Map<List<DocumentDto>>(items),
            TotalCount = totalItems,
            Page = page,
            PageSize = pageSize
        };
    }

    public async Task<DocumentDto?> GetDocumentByIdAsync(Guid userId, Guid id)
    {
        var document = await _documentRepository.GetByIdWithChunksAsync(id);
        if (document == null || document.UploadedBy != userId)
            return null;

        return _mapper.Map<DocumentDto>(document);
    }

    public async Task<bool> DeleteDocumentAsync(Guid userId, Guid id)
    {
        try
        {
            Console.WriteLine($"开始删除文档，用户ID: {userId}, 文档ID: {id}");

            // 直接查询数据库，不检查软删除状态
            var context = (ApplicationDbContext)_documentRepository.GetContext();
            var document = await context.Documents
                .FirstOrDefaultAsync(d => d.Id == id);

            if (document == null)
            {
                Console.WriteLine($"文档 {id} 不存在");
                return false;
            }

            if (document.UploadedBy != userId)
            {
                Console.WriteLine($"用户 {userId} 无权限删除文档 {id}，文档属于用户 {document.UploadedBy}");
                return false;
            }

            Console.WriteLine($"找到文档: {document.Title}, 开始删除...");

            try
            {
                // 先检查文档块数量
                var chunkCount = await context.DocumentChunks
                    .Where(dc => dc.DocumentId == id)
                    .CountAsync();
                Console.WriteLine($"文档 {id} 有 {chunkCount} 个文档块");

                // 使用原生SQL删除，避免EF Core的复杂性
                using var transaction = await context.Database.BeginTransactionAsync();
                try
                {
                    // 先删除文档块
                    var chunksDeleted = await context.Database.ExecuteSqlRawAsync(
                        "DELETE FROM document_chunks WHERE \"DocumentId\" = {0}", id);
                    Console.WriteLine($"删除了 {chunksDeleted} 个文档块");

                    // 再删除文档
                    var documentsDeleted = await context.Database.ExecuteSqlRawAsync(
                        "DELETE FROM documents WHERE \"Id\" = {0} AND \"UploadedBy\" = {1}", id, userId);
                    Console.WriteLine($"删除了 {documentsDeleted} 个文档");

                    if (documentsDeleted == 0)
                    {
                        Console.WriteLine("没有删除任何文档，可能是权限问题");
                        await transaction.RollbackAsync();
                        return false;
                    }

                    await transaction.CommitAsync();
                    Console.WriteLine($"文档 {id} 删除成功");
                    return true;
                }
                catch (Exception)
                {
                    await transaction.RollbackAsync();
                    throw;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"删除文档失败: {ex.Message}");
                Console.WriteLine($"异常类型: {ex.GetType().Name}");
                Console.WriteLine($"异常堆栈: {ex.StackTrace}");

                // 如果是数据库约束错误，提供更详细的信息
                if (ex.InnerException != null)
                {
                    Console.WriteLine($"内部异常: {ex.InnerException.Message}");
                }

                return false;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"删除文档时发生异常: {ex.Message}");
            Console.WriteLine($"异常类型: {ex.GetType().Name}");
            Console.WriteLine($"异常堆栈: {ex.StackTrace}");
            return false;
        }
    }

    public async Task<PagedResultDto<DocumentChunkDto>> GetDocumentChunksAsync(Guid userId, Guid documentId, int page = 1, int pageSize = 10)
    {
        var document = await _documentRepository.GetByIdAsync(documentId);
        if (document == null || document.UploadedBy != userId)
            return new PagedResultDto<DocumentChunkDto>();

        var chunks = await _documentChunkRepository.GetByDocumentIdAsync(documentId);
        var totalItems = chunks.Count();
        var pagedChunks = chunks
            .OrderBy(c => c.CreatedAt)
            .Skip((page - 1) * pageSize)
            .Take(pageSize);

        return new PagedResultDto<DocumentChunkDto>
        {
            Items = _mapper.Map<List<DocumentChunkDto>>(pagedChunks),
            TotalCount = totalItems,
            Page = page,
            PageSize = pageSize
        };
    }

    public async Task<bool> ReindexDocumentAsync(Guid userId, Guid documentId)
    {
        try
        {
            var document = await _documentRepository.GetByIdAsync(documentId);
            if (document == null || document.UploadedBy != userId)
                return false;

            // 删除现有的文档块
            var existingChunks = await _documentChunkRepository.GetByDocumentIdAsync(documentId);
            await _documentChunkRepository.RemoveRangeAsync(existingChunks);

            // 重新分块和嵌入
            await ChunkDocumentAsync(document);

            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }

    public async Task<List<DocumentChunk>> ChunkDocumentAsync(Document document, int chunkSize = 1000, int overlap = 200)
    {
        var chunks = await ChunkDocumentAsyncWithoutSave(document, chunkSize, overlap);
        await _documentChunkRepository.SaveChangesAsync();
        return chunks;
    }

    public async Task<List<DocumentChunk>> ChunkDocumentAsyncWithoutSave(Document document, int chunkSize = 1000, int overlap = 200)
    {
        if (string.IsNullOrWhiteSpace(document.Content))
            return new List<DocumentChunk>();

        var chunks = SplitTextIntoChunks(document.Content, chunkSize, overlap);
        var documentChunks = new List<DocumentChunk>();

        foreach (var chunkContent in chunks)
        {
            float[]? embedding;
            try
            {
                embedding = await _embeddingService.GenerateEmbeddingAsync(chunkContent);
            }
            catch (Exception ex)
            {
                // 如果嵌入服务失败，使用空的嵌入向量，但仍然保存文档块
                // 这样用户可以稍后重新索引
                embedding = null; // 使用null而不是空数组
                // 可以记录日志但不抛出异常
                Console.WriteLine($"嵌入服务失败: {ex.Message}");
            }

            var documentChunk = new DocumentChunk
            {
                DocumentId = document.Id,
                Content = chunkContent,
                Embedding = embedding,
                CreatedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow,
                CreateBy = document.UploadedBy?.ToString() ?? "system",
                UpdateBy = document.UploadedBy?.ToString() ?? "system",
                IsActive = true,
                IsDeleted = false
            };

            documentChunks.Add(documentChunk);
        }

        // 批量添加文档块到上下文，但不立即保存
        var chunkContext = (ApplicationDbContext)_documentChunkRepository.GetContext();
        await chunkContext.DocumentChunks.AddRangeAsync(documentChunks);
        return documentChunks;
    }

    private async Task<string> ReadFileContentAsync(IFormFile file)
    {
        using var reader = new StreamReader(file.OpenReadStream(), System.Text.Encoding.UTF8, detectEncodingFromByteOrderMarks: true);
        var content = await reader.ReadToEndAsync();

        // 清理可能导致数据库问题的字符
        content = content.Replace("\0", ""); // 移除空字节
        content = content.Replace("\uFEFF", ""); // 移除BOM

        return content;
    }

    private List<string> SplitTextIntoChunks(string text, int chunkSize, int overlap)
    {
        var chunks = new List<string>();
        var words = text.Split(new[] { ' ', '\n', '\r', '\t' }, StringSplitOptions.RemoveEmptyEntries);

        for (int i = 0; i < words.Length; i += chunkSize - overlap)
        {
            var chunkWords = words.Skip(i).Take(chunkSize).ToArray();
            if (chunkWords.Length > 0)
            {
                chunks.Add(string.Join(" ", chunkWords));
            }
        }

        return chunks;
    }
}